###############################################################################
# SuperLinks                                                                  #
# Copyright (c) 2000-2007 Greg Nolle (http://greg.nolle.co.uk)                #
###############################################################################
# This program is free software; you can redistribute it and/or modify it     #
# under the terms of the GNU General Public License as published by the Free  #
# Software Foundation; either version 2 of the License, or (at your option)   #
# any later version.                                                          #
#                                                                             #
# This program is distributed in the hope that it will be useful, but WITHOUT #
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or       #
# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for   #
# more details.                                                               ##                                                                             #
# You should have received a copy of the GNU General Public License along     #
# with this program; if not, write to the Free Software Foundation, Inc.,     #
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.                 #
###############################################################################
# ControlPanel/Update.pm.pl -> Update module                                  #
###############################################################################
# DON'T EDIT BELOW UNLESS YOU KNOW WHAT YOU'RE DOING!                         #
###############################################################################
package CP::Update;

BEGIN { require "System.pm.pl"; import System qw($SYSTEM); }
BEGIN { require "General.pm.pl"; import General qw($GENERAL); }
require "Error.pm.pl";
require "Standard.pm.pl";
require "Authenticate.pm.pl";
require "Logs.pm.pl";

use File::Path;
use File::Copy;
use Cwd;
use Archive::Tar;
use LWP::Simple;
use strict;

require "ControlPanel/Output/Update.pm.pl";

sub new {
  my ($class) = @_;
  my $self    = {};
  return bless($self, $class);
}

sub DESTROY { }

###############################################################################
# show subroutine
sub show {
  my $self = shift;
  my %in = (DB => undef, ERROR => "", @_);

  #----------------------------------------------------------------------#
  # Authenticating...                                                    #
  
  &Authenticate::CP(DB => $in{'DB'}, ACTION => "UPDATE");

  #----------------------------------------------------------------------#
  # Printing page...                                                     #

  my $Skin = Skin::CP::Update->new();

  &Standard::PrintHTMLHeader();
  print $Skin->show(error => $in{'ERROR'});
  
  return 1;
}

###############################################################################
# view subroutine
sub view {
  my $self = shift;
  my %in = (DB => undef, @_);

  #----------------------------------------------------------------------#
  # Authenticating...                                                    #
  
  &Authenticate::CP(DB => $in{'DB'}, ACTION => "UPDATE");

  #----------------------------------------------------------------------#
  # Checking fields...                                                   #
  
  my @Fields = (
    "SERVER",
    "USERNAME",
    "PASSWORD"
  );

  my @Error;
  foreach my $field (@Fields) {
    if (!$SL::QUERY{'FORM_'.$field}) {
      push(@Error, "MISSING-".$field);
    }
  }

  if (scalar(@Error) >= 1) {
    $self->show(DB => $in{'DB'}, ERROR => \@Error);
    return 1;
  }

  my $Result = getstore("http://$SL::QUERY{'FORM_USERNAME'}:$SL::QUERY{'FORM_PASSWORD'}\@$SL::QUERY{'FORM_SERVER'}/sl/updates.list", "$SYSTEM->{'TEMP_PATH'}/updates.list");
  if ($Result eq "401") {
    $self->show(DB => $in{'DB'}, ERROR => "INVALID-LOGIN");
    return 1;
  }	elsif ($Result ne "200") {
    $self->show(DB => $in{'DB'}, ERROR => "CONN-ERROR");
    return 1;
  }

  my (@Versions, $Start);
  
  &Standard::FileOpen(*LIST, "r", "$SYSTEM->{'TEMP_PATH'}/updates.list");
  foreach my $line (<LIST>) {
    my ($version, $file, $description) = split(/::/, $line);
    push(@Versions, { VERSION => $version, FILE => $file, DESCRIPTION => $description }) if ($Start);
    $Start = 1 if ($version eq $SL::VERSION);
  }
  close(LIST);

  unlink("$SYSTEM->{'TEMP_PATH'}/updates.list") || &Error::CGIError("Error removing updates list. $!", "$SYSTEM->{'TEMP_PATH'}/updates.list");

  my %INPUT;
  
  $INPUT{'VERSIONS'} = \@Versions;
  
  #----------------------------------------------------------------------#
  # Printing page...                                                     #

  my $Skin = Skin::CP::Update->new();

  &Standard::PrintHTMLHeader();
  print $Skin->view(input => \%INPUT);
  
  return 1;
}

###############################################################################
# do subroutine
sub do {
  my $self = shift;
  my %in = (DB => undef, @_);

  #----------------------------------------------------------------------#
  # Authenticating...                                                    #
  
  &Authenticate::CP(DB => $in{'DB'}, ACTION => "UPDATE");

  #----------------------------------------------------------------------#
  # Checking fields...                                                   #
  
  if (!$SL::QUERY{'FORM_SERVER'} || !$SL::QUERY{'FORM_USERNAME'} || !$SL::QUERY{'FORM_PASSWORD'}) {
    $self->show(DB => $in{'DB'});
    return 1;
  }
  if (!$SL::QUERY{'FORM_VERSION'}) {
    $self->view(DB => $in{'DB'});
    return 1;
  }

  my $Result = getstore("http://$SL::QUERY{'FORM_USERNAME'}:$SL::QUERY{'FORM_PASSWORD'}\@$SL::QUERY{'FORM_SERVER'}/sl/updates.list", "$SYSTEM->{'TEMP_PATH'}/updates.list");
  if ($Result eq "401") {
    $self->show(DB => $in{'DB'}, ERROR => "INVALID-LOGIN");
    return 1;
  }	elsif ($Result ne "200") {
    $self->show(DB => $in{'DB'}, ERROR => "CONN-ERROR");
  }

  my (@Versions, $Start, $End);
  &Standard::FileOpen(*LIST, "r", "$SYSTEM->{'TEMP_PATH'}/updates.list");
  foreach my $line (<LIST>) {
    my ($version, $file, $description) = split(/::/, $line);
    push(@Versions, { VERSION => $version, FILE => $file, DESCRIPTION => $description }) if ($Start);
    $Start = 1 if ($version eq $SL::VERSION);
    $End = 1 and last if ($version eq $SL::QUERY{'FORM_VERSION'});
  }
	close(LIST);

  unlink("$SYSTEM->{'TEMP_PATH'}/updates.list") || &Error::CGIError("Error removing updates list. $!", "$SYSTEM->{'TEMP_PATH'}/updates.list");
	
	unless ($Start && $End) {
	  $self->view(DB => $in{'DB'});
	  return 1;
	}

  #----------------------------------------------------------------------#
  # Preparing data...                                                    #

  my $Skin = Skin::CP::Update->new();

  &Standard::PrintHTMLHeader();  

  unless ($SL::QUERY{'do'}) {
    print $Skin->do();
    return 1;
  }

  my $Log = Logs->new(PRINT => 1);

  my $Exit = eval {
    sub {
      $Log->Footer();
      exit;
    }
  };

  $Log->Header();

  $Log->Line("", "uplevel");
  $Log->Line("Beginning update...\n\n", "element");
  
  mkdir("$SYSTEM->{'TEMP_PATH'}/Update", 0777);
  chmod(0777, "$SYSTEM->{'TEMP_PATH'}/Update");

  my $count = 1;
  foreach my $version (@Versions) {
    $Log->Line("Upgrading to $version->{'DESCRIPTION'}...", "element");
    $Log->Line("", "uplevel");
    $Log->Line("Downloading update package... ", "element");
    my $result = getstore("http://$SL::QUERY{'FORM_USERNAME'}:$SL::QUERY{'FORM_PASSWORD'}\@$SL::QUERY{'FORM_SERVER'}/sl/$version->{'FILE'}", "$SYSTEM->{'TEMP_PATH'}/Update/$version->{'FILE'}");
    if ($result eq "200") {
      $Log->Line("Done.", "success");
    } else {
      $Log->Line("Error: $result", "error") and &$Exit;
    }

    $Log->Line("Checking package... ", "element");
    if ($version->{'FILE'} =~ /\.tar$/i || $version->{'FILE'} =~ /\.pak$/i) {
      $Log->Line("Seems OK.", "success");
    }	else {
      $Log->Line("Error: Package is not valid.", "error") and &$Exit;
    }

    if ($version->{'FILE'} =~ /\.tar$/i) {
      $Log->Line("Unpacking package... ", "element");
			
      mkdir("$SYSTEM->{'TEMP_PATH'}/Package$count", 0777) || ($Log->Line("Error: $!", "error") and &$Exit);
      chmod(0777, "$SYSTEM->{'TEMP_PATH'}/Package$count");
			
      my $tar = Archive::Tar->new();
         $tar->read("$SYSTEM->{'TEMP_PATH'}/Update/".$version->{'FILE'}, 0);
			
      my $SLd = cwd();
      chdir("$SYSTEM->{'TEMP_PATH'}/Package$count");
      my @files = $tar->list_files();
      $tar->extract(@files);
      chdir($SLd);

      $Log->Line("Done.", "success");
    } else {
      $Log->Line("Copying install.pak... ", "element");
      mkdir("$SYSTEM->{'TEMP_PATH'}/Package$count", 0777) || ($Log->Line("Error: $!", "error") and &$Exit);
      chmod(0777, "$SYSTEM->{'TEMP_PATH'}/Package$count");
      copy("$SYSTEM->{'TEMP_PATH'}/Update/$version->{'FILE'}", "$SYSTEM->{'TEMP_PATH'}/Package$count/install.pak") || ($Log->Line("Error: $!", "error") and &$Exit);
      $Log->Line("Done.", "success");
    }
		
    $Log->Line("Executing package...", "element");
    $Log->Line("", "uplevel");

    eval {
      require "$SYSTEM->{'TEMP_PATH'}/Package$count/install.pak";
      my $PACK = Package->new();
         $PACK->Main($Log, $Exit, "$SYSTEM->{'TEMP_PATH'}/Package$count");
    };
    if ($@) {
      $Log->Line("Error: $@", "error") and &$Exit;
    }
    
    $Log->Line("", "downlevel");
		
    $Log->Line("Finished executing package. Deleting installation files... ", "element");
    unless (rmtree("$SYSTEM->{'TEMP_PATH'}/Package$count")) {
      $Log->Line("Error: $!", "error") and &$Exit;
    }
    unless (unlink("$SYSTEM->{'TEMP_PATH'}/Update/$version->{'FILE'}")) {
      $Log->Line("Error: $!", "error") and &$Exit;
    }
    $Log->Line("Done.", "success");
    
    $Log->Line("", "downlevel");
    $count++;
  }

  $Log->Line("Update complete. Deleting installation files... ", "element");
  if (rmtree("$SYSTEM->{'TEMP_PATH'}/Update")) {
    $Log->Line("Done.", "success");
  }	else {
    $Log->Line("Error: $!", "error");
  }

  $Log->Line("\n\n", "");
  $Log->Line("All done!", "element");
  $Log->Line("", "downlevel");

  &$Exit;
}

1;